<?php

include_once(_CORE_PATH. "mapper_prototype.php");
include_once(_APP_PATH. "business/users/users_entity.php");
class UsersMapper extends mapper_prototype
{
	
	private $_user;
	private $_source;
	
	public function __construct(active_user_class $user)
	{
		parent::__construct('users');
		$this->_user = $user;
		
		$this->_source = MozgSource::get('default');
	}	
	
	static public function GetInstance(active_user_class $user)
	{
		return new self($user);		
	}
	
	private function User()
	{ 
		if (!$this->_user) throw new Exception('Юзер не определён');
    	return $this->_user; 
	}	
	
	public function GetSuperUser()
	{
		$obj = new UsersEntity();
		$obj->SetUserId(0);
		
		$superUser = MozgCfg::GetProp('global/users//superUser');
		
		$obj->SetUserName($superUser['userName']);
		$obj->SetPasswordHash($superUser['password']);
		$obj->SetUserGroup($superUser['groupId']);
		$obj->SetGroupName($superUser['groupName']);
		$obj->SetEmail($superUser['email']);
		$obj->SetBlocked(0);
		return $obj;
	}
	
	public function GetByLoginPassword($login, $password)
	{
		if ($login == MozgCfg::GetProp('global/users//superUser/userName'))
		{
			$user = $this->GetSuperUser();
		}
		else
		{
			$user = $this->GetByProp('u.username', $login);
			if (!$user) return false;
		}

		if (!$this->Libs()->passhash->CheckPassword($password, $user->GetPasswordHash())) return false;
		return $user;
	}
	
	public function GetById($id)
	{
          return $this->GetByProp('u.user_id', (int)$id);		
	}
	
	private function GetByProp($propName, $propValue)
	{
          return $this->_source->query("SELECT
											   u.user_id userId,
							                   u.username userName,
							                   u.fullname fullName,
							                   u.email email,
							                   u.blocked blocked,
							                   g.id userGroup,
							                   g.title groupName,
							                   u.avatar,
							                   u.passwd passwordHash,
							                   u.granted_groups grantedGroupsNorm
						                     FROM
						                     	%%users%% u
						                     		left join %%user_groups%% g on(u.user_group=g.id)
						                     WHERE
						                     	" .$propName. "=" .$this->_source->quote($propValue). "
						                    ")->fetchObject('UsersEntity');			
	}
	
	public function GetNew()
	{
		return new UsersEntity();
	}
	
	private $_totalRows = 0;
	
	public function GetTotal()
	{
		return $this->_totalRows;		
	}
	
	public function GetUsers($paginator)
	{   
        $stmt = $this->_source->query("SELECT SQL_CALC_FOUND_ROWS
												   u.user_id userId,
								                   u.username userName,
								                   u.fullname fullName,
								                   u.user_group userGroup,
								                   u.blocked blocked,
								                   g.title groupName,
								                   u.avatar,
								                   u.granted_groups grantedGroupsNorm
							                 FROM %%users%% u
							                 		left join %%user_groups%% g on(u.user_group=g.id)
							                 WHERE
					                              (g.id is NULL
					                              " . (sizeof($this->User()->GetAvailableGroups()) ? ' OR g.id in (' . implode(',', $this->User()->GetAvailableGroups()) . ') ' : '') . " )
							                 ORDER by u.user_group, u.user_id
							                 LIMIT " . $paginator->GetSqlLimit() . "
							               ");

        $this->_totalRows = $this->_source->query("SELECT FOUND_ROWS()")->fetchColumn();
        
	    $stmt->setFetchMode(PDO::FETCH_CLASS, 'UsersEntity');
        return $stmt->fetchAll();		
	}
	
	public function Save(UsersEntity $obj)
	{
		if (!$this->Prepare($obj)) return false;
		
		if ($obj->GetUserId())
		{
			return $this->Update($obj);		
		}

		return $this->Insert($obj);
	}
	
	private function Insert(UsersEntity $obj)
	{
		if (strlen($obj->GetPassword() < 6)) 
		{
			return $this->SetErrorMessage('Пароль должен быть не короче 6-ти символов');
		}
		
		$num = $this->_source->exec("insert into %%users%%(user_group, username, fullname, email, passwd, blocked, update_time, avatar, granted_groups)
			            values(
					              '" .$obj->GetUserGroup(). "',
					              " .$this->_source->quote($obj->GetUserName()). ",
					              " .$this->_source->quote($obj->GetFullName()). ",
					              " .$this->_source->quote($obj->GetEmail()). ",
					              '" .$this->Libs()->passhash->HashPassword($obj->GetPassword()). "',
					              '" .$obj->GetBlocked(). "',
					              NOW(),
					              " .$this->_source->quote($obj->GetNewAvatar()). ",
					              " .$this->_source->quote($obj->GetGrantedGroupsNorm()). "
			            )
			");		
	
		if ($num)
		{
			$obj->SetUserId($this->_source->lastInsertID());
			
			if ($obj->GetNewAvatar())
			{
				$obj->SetAvatar($obj->GetNewAvatar());
			}				
			
			return true;
		}
		
		$this->DelAvatars($obj->GetNewAvatar());
		
		return false;
	}
	
	private function Update(UsersEntity $obj)
	{
		if (strlen($obj->GetPassword()) && (strlen($obj->GetPassword() < 6))) 
		{
			return $this->SetErrorMessage('Пароль должен быть не короче 6-ти символов');
		}
		
		$num = (bool)$this->_source->exec("update %%users%% u
							                 		left join %%user_groups%% g on(u.user_group=g.id) 
										      set
										       	 u.user_group=" .$obj->GetUserGroup(). ",
										         u.username=" .$this->_source->quote($obj->GetUserName()). ",
										         u.fullname=" .$this->_source->quote($obj->GetFullName()). ",
										         u.email=" .$this->_source->quote($obj->GetEmail()). ",
										         " . (strlen($obj->GetPassword()) ? "u.passwd='" . $this->Libs()->passhash->HashPassword($obj->GetPassword()) . "'," : '') . "
										         u.blocked=" .$obj->GetBlocked(). ",
										         u.update_time = NOW(),
										         u.avatar = " .$this->_source->quote($obj->GetNewAvatar()). ",
										         u.granted_groups = " .$this->_source->quote($obj->GetGrantedGroupsNorm()). "
										      where 
										      	 u.user_id='" .$obj->GetUserId(). "' and
										      	 (g.id is NULL OR
										      	  u.user_id='" .$this->User()->GetId(). "'
						                          " . (sizeof($this->User()->GetAvailableGroups()) ? ' OR g.id in (' . implode(',', $this->User()->GetAvailableGroups()) . ') ' : '') . " )
									     ");		
	
		if ($num)
		{
			if ($obj->GetNewAvatar())
			{
				$this->DelAvatars($obj->GetAvatar());	
				$obj->SetAvatar($obj->GetNewAvatar());
			}			
			
			return true;
		}
		
		$this->DelAvatars($obj->GetNewAvatar());
		
		return false;
	}	
	
    private function GenerateAvatarName()
    {
        return uniqid();
    }		
	
	private function SaveAvatar($tempPhoto, $newFileName)
	{
		include_once(_APP_PATH. "business/image/image_mapper.php");
		$imageMapper = ImageMapper::GetInstance();
		return $imageMapper->UploadResize(_ROOT_PATH.MozgCfg::getProp('global/users//avatarImageFolder'), $newFileName, $tempPhoto, MozgCfg::GetProp('global/image//photoMaxSize'));
	}	
	
	private function Prepare(UsersEntity $obj)
	{
		if (strlen($obj->GetUserName()) < 4) 
		{
            return $this->SetErrorMessage('Логин должен быть не короче 4-х символов');
        }
        
        if (!preg_match('/^[a-z_\-0-9.]+$/uis', $obj->GetUserName())) 
        {
            return $this->SetErrorMessage('Логин содержит не допустимые символы');
        }
    
	    $r = $this->_source->query("SELECT 
        										user_id userId 
        									FROM %%users%% 
        									WHERE 
        										user_id!='" . $obj->GetUserId() . "' and 
        										username=" . $this->_source->quote($obj->GetUserName()))->fetchColumn();        

        if ($r) 
        {
            return $this->SetErrorMessage('Такой логин уже существует');
        }        
        
        if (($this->User()->GetId() != $obj->GetUserId()) && !in_array($obj->GetUserGroup(), $this->User()->GetAvailableGroups())) 
        {
            return $this->SetErrorMessage('Выберите основную группу');
        }

		if ($obj->GetTempAvatar())
		{	
			$obj->SetNewAvatar($this->SaveAvatar($obj->GetTempAvatar(), $this->GenerateAvatarName()));
		}        
        
        return true;
	}	
	
    public function Delete($userId)
    {
    	$userId = (int)$userId;
    	if (!$userId) return false;

        $avatar = $this->_source->query("SELECT 
		        									avatar
		        								FROM %%users%%
		        								WHERE 
		        									user_id='" .$userId. "'
		        								")->fetchColumn();      	
    	
        $num = (bool)$this->_source->exec("DELETE 
		        									u, ugg
		        								FROM %%users%% u
								                 		left join %%user_groups%% g on(u.user_group=g.id)
								                 		left join %%user_granted_groups%% ugg on (u.user_id=ugg.user_id) 
		        								WHERE 
		        									u.user_id='" .$userId. "' and
													(g.id is NULL
						                             " . (sizeof($this->User()->GetAvailableGroups()) ? ' OR g.id in (' . implode(',', $this->User()->GetAvailableGroups()) . ') ' : '') . " )        									 
		        							");
    
    	if ($num)
    	{
			$this->DelAvatars($avatar);     		
    		return true;
    	}
    	
    	return false;
    }	
	
    public function GetGrantedGroups($userId)
    {
        return $this->_source->query("SELECT
												   group_id groupId
							                 FROM %%user_granted_groups%%
							                 WHERE
					                              user_id='" . (int)$userId . "'
							               ")->fetchAll(PDO::FETCH_COLUMN);
    }
    public function SaveGrantedGroups ($userId, array $groups)
    {
    	$myGroups = $this->User()->GetAvailableGroups();       
    	if (!sizeof($myGroups)) return false;
        
    	$this->_source->exec("DELETE FROM %%user_granted_groups%% WHERE group_id in ('" . implode("','", $myGroups) . "') and user_id=" .(int)$userId);
        
        $groups = array_intersect($groups, $myGroups);
        
        $sql = array();
        while (list (, $v) = each($groups)) 
        {
            $sql[] = '("' . $userId . '", "' . $v . '")';
        }
        
        if (sizeof($sql)) 
        {
            return (bool)$this->_source->exec("INSERT INTO %%user_granted_groups%% (user_id, group_id)
					              					VALUES " . implode(',', $sql) . "
					            				");
        }
        
        return false;
    }	
	
    private function DelAvatars($avatars)
    {
    	if (!$avatars) return;
		if (!is_array($avatars)) $avatars = array($avatars);  
   	    foreach ($avatars as $avatar)
       	{
			if (!$avatar || ($avatar == MozgCfg::GetProp('global/users//noAvatar')) || !is_file(_ROOT_PATH.MozgCfg::GetProp('global/users//avatarImageFolder').$avatar)) continue;
			@unlink(_ROOT_PATH.MozgCfg::GetProp('global/users//avatarImageFolder').$avatar);        		
       	}   		  	
    }    
    
	public function GetUsersByName($name, $maxRecords = 50, $isExactSearch = false)
	{   
		if ($this->Libs()->str->Len($name) < 2) return array();
        
		$sqlName = str_replace('%', '\%', $this->_source->quote($name));
		$sqlName = rtrim($sqlName, "'").(!$isExactSearch ? '%' : ''). "'";
		$stmt = $this->_source->query("SELECT
												user_id userId,
												username userName
							                 FROM 
							                 	%%users%%	
							                 WHERE
							                 	username LIKE " .$sqlName. "	              																 
							                 ORDER by username
							                 LIMIT 0, " .(int)$maxRecords. "
							               ");

	    $stmt->setFetchMode(PDO::FETCH_CLASS, 'UsersEntity');
        return $stmt->fetchAll();		
	}    
}